/********************************************
 * 文件名称: FtpClient.java
 * 系统名称: 第三方前置系统V1.0
 * 模块名称:
 * 软件版权: 恒生电子股份有限公司
 * 功能说明: 
 * 系统版本: 1.0.0.0
 * 开发人员: fansg
 * 开发时间: 2013-7-9 上午11:40:47
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期      修改人员    修改说明
 *********************************************/

package org.fnzn.util.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import cn.hutool.core.io.FileUtil;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;


public class FtpImpl implements Ftp{
	private FTPClient ftpClient;
	public static final int BINARY = FTP.BINARY_FILE_TYPE;
	public static final int ASCII = FTP.ASCII_FILE_TYPE;
	
	
	public FtpImpl(){
		ftpClient = new FTPClient();
		ftpClient.setControlEncoding("GBK");
    }
	
	/**
	 * 文件传输编码方式，默认编码方式GBK
	 * @param encoding
	 */
	public void setControlEncoding(String encoding){
		ftpClient.setControlEncoding(encoding);
	}
	
	/**
	 * 连接远程ftp服务器
	 * @param server 服务器ip 或者机器名
	 * @param port  端口
	 * @param user  用户名
	 * @param password  密码
	 * @throws SocketException
	 * @throws IOException
	 */
	public void connect(String server, int port, String user,
			String password) throws SocketException, IOException {
		this.connect(server, port, user, password,"");
	}
	
	/**
	 * 连接远程ftp服务器
	 * @param server ip 或者机器名称
	 * @param port   端口
	 * @param user   用户名
	 * @param password  用户密码
	 * @param path     远程路径
	 * @throws SocketException
	 * @throws IOException
	 */
	public void connect(String server, int port, String user,
			String password, String path) throws SocketException, IOException {
		ftpClient.setConnectTimeout(60000);//设置连接超时时间
		ftpClient.connect(server, port);
		
		int reply = ftpClient.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply))
        {
        	 ftpClient.disconnect();
             throw new SocketException("FTP server refused connection");
        }
		
        //ADDED BY JYH 20110718-01 BEGIN
		boolean  flag= ftpClient.login(user, password);
		if(!flag){
			throw new RuntimeException("ftp login fail! username or password error ");
		}
		//ADDED BY JYH 20110718-01 END
		
		if (null != path && path.length() != 0) {
			ftpClient.changeWorkingDirectory(path);
		}
		//MODIFIED BY  JYH  20120701-01 BEGIN
		try{
		   String pasvMode=System.getProperty("hs.ftp.client.pasv.mode", "true");
		   if("false".equals(pasvMode)){
               ftpClient.enterLocalActiveMode();			   
		   }else{
			   ftpClient.enterLocalPassiveMode();
		   }
		}catch(Exception  e){
			ftpClient.enterLocalPassiveMode();
		}
		//ftpClient.enterLocalPassiveMode();
		
		//MODIFIED BY JYH  20120701-01 END
	}

	/**
	 * 设置文件传输类型
	 * FTP.BINARY_FILE_TYPE 二进制类型
	 * FTP.ASCII_FILE_TYPE  文本类型
	 * @param fileType 文件类型
	 * @throws IOException
	 */
	public void setFileType(int fileType) throws IOException {
		ftpClient.setFileType(fileType);
	}
	
	public void bin()throws IOException{
		this.setFileType(FtpImpl.BINARY);
	}
	
	public void asc()throws IOException{
		this.setFileType(FtpImpl.ASCII);
	}

	/**
	 * 关闭ftp连接
	 * @throws IOException
	 */
	public void close() throws IOException {
		if (ftpClient != null && ftpClient.isConnected()) {
			try {
				ftpClient.logout();
			} catch (IOException e) {
				throw e;
			} finally {
				ftpClient.disconnect();
				ftpClient = null;
			}
		}
	}

	/**
	 * 切换路径
	 * @param path 路径
	 * @return
	 * @throws IOException
	 */
	public boolean cd(String path) throws IOException {
		return ftpClient.changeWorkingDirectory(path);
	}

	/**
	 * 建立路径,如果路径不存在则建立
	 * @param pathName  路径名称
	 * @return
	 * @throws IOException
	 */
	public boolean mkdir(String pathName) throws IOException {
		if(!this.existDirectory(pathName)){
			StringTokenizer st = new StringTokenizer(pathName, "/");
			String path = "";
			while (st.hasMoreTokens()) {
				path += "/" + st.nextToken();
				if (!this.existDirectory(path)){
					if(!ftpClient.makeDirectory(path)){
						return false;
					}
				}
			}
		}
		return true;
	}

	/**
	 * 删除目录
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public boolean rm(String path) throws IOException {
		return ftpClient.removeDirectory(path);
	}

    /**
     * 删除目录极其子目录
     * @param path   目录
     * @param isAll  是否删除子目录
     * @return
     * @throws IOException
     */
	public boolean rm(String path, boolean isAll)
			throws IOException {

		if (!isAll) {
			return rm(path);
		}

		FTPFile[] ftpFileArr = ftpClient.listFiles(path);
		if (ftpFileArr == null || ftpFileArr.length == 0) {
			return rm(path);
		}
		//    
		for (FTPFile ftpFile : ftpFileArr) {
			String name = ftpFile.getName();
			if (ftpFile.isDirectory()) {
				
				rm(path + "/" + name, true);
			} else if (ftpFile.isFile()) {
				
				deleteFile(path + "/" + name);
			} else if (ftpFile.isSymbolicLink()) {

			} else if (ftpFile.isUnknown()) {

			}
		}
		return ftpClient.removeDirectory(path);
	}

    /**
     * 检查目录是否存在
     * @param path  路径
     * @return
     * @throws IOException
     */
	public boolean existDirectory(String path) throws IOException {
//		boolean flag = false;
//		FTPFile[] ftpFileArr = ftpClient.listFiles(path);
//		for (FTPFile ftpFile : ftpFileArr) {
//			if (ftpFile.isDirectory()
//					&& ftpFile.getName().equalsIgnoreCase(path)) {
//				flag = true;
//				break;
//			}
//		}
//		return flag;
		String currWorkingPath = ftpClient.printWorkingDirectory();
		try{
			if(cd(path)){
				return true;
			}
		}catch(IOException e){
			throw e;
		}finally{
			cd(currWorkingPath);
		}
		return false;
	}

	/**
	 * 获取指定目录文件名列表
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public List<String> getFileList(String path) throws IOException {
		// listFiles return contains directory and file, it's FTPFile instance
		// listNames() contains directory, so using following to filer
		// directory.
		// String[] fileNameArr = ftpClient.listNames(path);
		FTPFile[] ftpFiles = ftpClient.listFiles(path);

		List<String> retList = new ArrayList<String>();
		if (ftpFiles == null || ftpFiles.length == 0) {
			return retList;
		}
		for (FTPFile ftpFile : ftpFiles) {
			if (ftpFile.isFile()) {
				retList.add(ftpFile.getName());
			}
		}
		return retList;
	}

	/**
	 * 删除ftp服务器上的文件
	 * @param pathName  
	 * @return
	 * @throws IOException
	 */
	public boolean deleteFile(String pathName) throws IOException {
		return ftpClient.deleteFile(pathName);
	}

    /**
     * 上传文件到指定服务器
     * @param fileName 待上传文件名称
     * @param newName  上传的文件名称
     * @return
     * @throws IOException
     */
	public boolean uploadFile(String fileName, String newName)
			throws IOException {
		boolean flag = false;
		InputStream iStream = null;
		try {
			iStream = new FileInputStream(fileName);
			flag = ftpClient.storeFile(newName, iStream);
		} catch (IOException e) {
			flag = false;
			return flag;
		} finally {
			if (iStream != null) {
				iStream.close();
			}
		}
		return flag;
	}

	/**
	 * 上传文件
	 * @param fileName  文件名称
	 * @return
	 * @throws IOException
	 */
	public boolean uploadFile(String fileName) throws IOException {
		return uploadFile(fileName, fileName);
	}

    /**
     * 下载文件
     * @param remoteFileName  远程文件名称
     * @param localFileName   本地文件名称
     * @return
     * @throws IOException
     */
	public boolean download(String remoteFileName, String localFileName)
			throws IOException {
		boolean flag = false;
		File outfile = new File(localFileName);
		OutputStream oStream = null;
		try {
			oStream = new FileOutputStream(outfile);
			flag = ftpClient.retrieveFile(remoteFileName, oStream);
		} catch (IOException e) {
			flag = false;
			return flag;
		} finally {
			if(oStream!=null){
			    oStream.close();
			}
		}
		//ADDED BY JYH 20101023-01 BEGIN
		if(flag==false){
			//下载失败，删除中间产物文件
			FileUtil.del(localFileName);
			
		}
		//ADDED BY JYH 20101023-01 END
		
		return flag;
	}

    @Override
    public InputStream downloadStream(String remoteFileName) {
        InputStream inputStream = null;
        try {
            inputStream = ftpClient.retrieveFileStream(remoteFileName);
        } catch (IOException e) {
            return null;
        } 
        return inputStream;
    }
	
}
